/*******************************************************************************
 * @file      lwheap.h
 * @brief     轻量级动态内存管理
 *
 * @history   V0.01, 2018-11-03, xiaoguolin, first implementation.
*******************************************************************************/
#ifndef LWHEAP_H
#define LWHEAP_H

#ifdef __cplusplus
extern "C"{
#endif //__cplusplus

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

/******************************************************************************/

/**
 * 记录内存使用量
 * 0 - 不记录内存使用量(缺省默认值)
 * 1 - 记录内存使用量
 */
#define LWHEAP_ENABLE_MEMEORY_USE_RECORD       1

/**
 * 内存追踪支持, 可用于调试内存泄漏问题
 * 0 - 关闭内存追踪功能(缺省默认值)
 * 1 - 开启追踪功能, 速度较慢, 但占用更少的内存
 * 2 - 开启追踪功能, 速度更快, 但占用较多的内存
 */
#define LWHEAP_MEMORY_TRACE_LEVEL              0

/**
 * 内存追踪存储数据类型, LWHEAP_MEMORY_TRACE_LEVEL!=0时有效
 * 0 - 用户自定义类型
 * 1 - 仅字符串类型
 * 2 - 函数名以及文件行号(缺省默认值)
 */
#define LWHEAP_USER_TRACE_DATA_TYPE            2

#define __LWHEAP_WEAK                          __attribute__((weak))

/******************************************************************************/

#ifndef LWHEAP_ENABLE_MEMEORY_USE_RECORD
    #define LWHEAP_ENABLE_MEMEORY_USE_RECORD   1
#endif
#ifndef LWHEAP_MEMORY_TRACE_LEVEL
    #define LWHEAP_MEMORY_TRACE_LEVEL          0
#endif
#ifndef LWHEAP_USER_TRACE_DATA_TYPE
    #define LWHEAP_USER_TRACE_DATA_TYPE        2
#endif
#ifndef __LWHEAP_WEAK
    #define __LWHEAP_WEAK /* nothing */
#endif


#define __LWHEAP_DATA_FLAG_USER_TRACE     0xFFFFFFFFul
#define __LWHEAP_DATA_FLAG_MALLOC_FAILED  0xFFFFFFFEul
#define __LWHEAP_DATA_FLAG_INNER_USE      0xFFFFFFFDul

#define __LWHEAP_DATA_FLAG_USE_OLD        0xFFFFFFF0ul

#define __LWHEAP_DATA_FLAG_MIN_VALUE      0xFFFFFFF0ul




typedef uint32_t LwHeap_Size_t;

typedef struct __LwHeap_Block
{
    LwHeap_Size_t          size;    //内存块大小, 包括block头
#if LWHEAP_MEMORY_TRACE_LEVEL != 0
#if LWHEAP_USER_TRACE_DATA_TYPE == 0
    void*                  __data;  //用户数据, 用户可用来进行调试追踪
    LwHeap_Size_t          __dlen;  //用户数据长度
#elif LWHEAP_USER_TRACE_DATA_TYPE == 1
    char*                  __ustr;  //用户数据, 用于追踪调试的字符串信息
#elif LWHEAP_USER_TRACE_DATA_TYPE == 2
    char*                  __func;  //函数名
    uint32_t               __line;  //文件行号
#else
#error LWHEAP_USER_TRACE_DATA_TYPE的值错误
#endif
#if LWHEAP_MEMORY_TRACE_LEVEL == 2
    struct __LwHeap_Block* __prev;  //前一个block指针, 配合调试追踪使用
#endif
    struct __LwHeap_Block* __next;  //后一个block指针, 配合调试追踪使用
#endif
    struct __LwHeap_Block* next;    //下一内存块地址
}LwHeap_Block_t;

typedef struct
{
    LwHeap_Block_t freeBlockListHeader;
#if LWHEAP_MEMORY_TRACE_LEVEL != 0
    LwHeap_Block_t usedBlockListHeader;
#endif
#if LWHEAP_ENABLE_MEMEORY_USE_RECORD != 0
    struct{
        uint32_t total;
        uint32_t free;
        uint32_t minval;
    }memCount;
#endif
}LwHeap_t;

void  LwHeap_Init  (LwHeap_t* heap);
bool  LwHeap_AddMem(LwHeap_t* heap, void* mptr, LwHeap_Size_t mlen);

#if LWHEAP_ENABLE_MEMEORY_USE_RECORD != 0
#define LwHeap_GetTotoalSize(heap)      ((heap)->memCount.total)
#define LwHeap_GetFreeSize(heap)        ((heap)->memCount.free)
#define LwHeap_GetMinFreeSize(heap)     ((heap)->memCount.minval)
#define lwheap_get_totalsize         LwHeap_GetTotoalSize
#define lwheap_get_freesize          LwHeap_GetFreeSize
#define lwheap_get_minfreesize       LwHeap_GetMinFreeSize
#endif

#if LWHEAP_MEMORY_TRACE_LEVEL != 0
#if LWHEAP_USER_TRACE_DATA_TYPE == 0
void* LwHeap_Malloc(LwHeap_t* heap, LwHeap_Size_t reqsize, int align, const void* udat, LwHeap_Size_t usiz);
void* LwHeap_Realloc(LwHeap_t* heap, void* mptr, LwHeap_Size_t newsize, int align, const void* udat, LwHeap_Size_t usiz);
#define lwheap_malloc               LwHeap_Malloc
#define lwheap_realloc              LwHeap_Realloc
#define lwheap_calloc(heap, n, size, align, udat, usiz)   lwheap_malloc((heap),(n)*(size),(align),(udat),(usiz))
#elif LWHEAP_USER_TRACE_DATA_TYPE == 1
void* LwHeap_Malloc(LwHeap_t *heap, LwHeap_Size_t reqsize, int align, const char* ustr);
void* LwHeap_Realloc(LwHeap_t *heap, void *mptr, LwHeap_Size_t newsize, int align, const char* ustr);
#define lwheap_malloc               LwHeap_Malloc
#define lwheap_realloc              LwHeap_Realloc
#define lwheap_calloc(heap, n, size, align, ustr)         lwheap_malloc((heap),(n)*(size),(align),(ustr))
#elif LWHEAP_USER_TRACE_DATA_TYPE == 2
void* LwHeap_Malloc(LwHeap_t *heap, LwHeap_Size_t reqsize, int align, const char* func, uint32_t line);
void* LwHeap_Realloc(LwHeap_t *heap, void *mptr, LwHeap_Size_t newsize, int align, const char *func, uint32_t line);
#define lwheap_malloc(heap, size, align)            LwHeap_Malloc((heap),(size),(align),__FUNCTION__,__LINE__)
#define lwheap_realloc(heap, mptr, nsize, align)    LwHeap_Realloc((heap),(mptr),(nsize),(align),__FUNCTION__,__LINE__)
#define lwheap_calloc(heap, n, size, align)         lwheap_malloc((heap),(n)*(size),(align))
#endif //LWHEAP_USER_TRACE_DATA_TYPE
#else
void* LwHeap_Malloc(LwHeap_t* heap, LwHeap_Size_t reqsize, int align);
void* LwHeap_Realloc(LwHeap_t* heap, void* mptr, LwHeap_Size_t newsize, int align);
#define lwheap_malloc               LwHeap_Malloc
#define lwheap_realloc              LwHeap_Realloc
#define lwheap_calloc(heap, n, size, align)         lwheap_malloc((heap),(n)*(size),(align))
#endif //LWHEAP_MEMORY_TRACE_LEVEL
bool  LwHeap_Free  (LwHeap_t* heap, void* mptr);
#define lwheap_free                 LwHeap_Free

/******************************************************************************/

#define LWHEAP_ITERATOR_FLAG_FREE_LIST        0
#define LWHEAP_ITERATOR_FLAG_USED_LIST        1

typedef struct __LwHeap_Iterator
{
    LwHeap_t*       heap;
    LwHeap_Block_t* prevBlock;
    LwHeap_Block_t* currBlock;
    uint32_t        flags;
}LwHeap_Iterator_t;

typedef struct __LwHeap_IteratorData
{
    const LwHeap_Block_t* blockAddr;
    LwHeap_Size_t         blockSize;
    union{
        struct{
            const LwHeap_Block_t* nextBlock;
            const void*           userPointer;
        }free;
#if LWHEAP_MEMORY_TRACE_LEVEL != 0
        struct{
            const LwHeap_Block_t* prevBlock;
            const LwHeap_Block_t* nextBlock;
            const void*           userPointer;
#if LWHEAP_USER_TRACE_DATA_TYPE == 0
            const void* data;
            uint32_t    dlen;
#elif LWHEAP_USER_TRACE_DATA_TYPE == 1
            const char* ustr;
#elif LWHEAP_USER_TRACE_DATA_TYPE == 2
            const char* func;
            uint32_t    line;
#endif
        }used;
#endif
    }type;
}LwHeap_IteratorData_t;

LwHeap_Iterator_t* LwHeap_IteratorBegin(LwHeap_t* heap, uint32_t flag);
bool LwHeap_IteratorRead(LwHeap_Iterator_t* iterator, LwHeap_IteratorData_t* pdata);
void LwHeap_IteratorEnd(LwHeap_Iterator_t* iterator);
#define lwheap_iterator_begin       LwHeap_IteratorBegin
#define lwheap_iterator_read        LwHeap_IteratorRead
#define lwheap_iterator_end         LwHeap_IteratorEnd

#ifdef __cplusplus
}
#endif //__cplusplus

#endif // LWHEAP_H
